fiber reconciler
什么是 fiber
fiber翻译过来是纤维的意思,是 React 16 版本以后针对组件设计的一个对象的数据结构,一个 React 组件就对应一个fiber节点,其保存组件内部一些属性或者方法:
-
type:组件的类型 -
key:组件更新的标记 -
child:对应当前组件渲染的子组件 -
sibling:当一个组件返回多个子元素的组成的数组时,sibling就表示子组件的兄弟组件 -
return:当前组件的父节点 -
pendingProps和memoizedProps:分别代表更新的props属性和当前props属性,如果更新后的这俩值相同就表示当前节点可以直接复用 -
pendingWorkPriority:一个代表组件更新优先级的数字 -
output:一个包含最终输出的 DOM 节点的数据结构,最终会传递给renderer去选择创建、更新到 UI 上去 -
alternate:当前fiber在另一次更新时对应的fiber
完整的fiber节点属性在源码这里。
两种类型的 fiber 节点
在任何时候,一个组件的实例最多存在两种类型的fiber节点:
current fiber:当前已经渲染出来的fiber节点;work-in-progress fiber:正在内存中构建的fiber节点,也就是下一次更新可能会被渲染的
两种节点之间通过上述的alternate属性关联,current fiber的alternate指向work-in-progress fiber,而work-in-progress fiber则指向current fiber。
currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;
采用两种类型fiber节点的原因主要是为了复用fiber节点的状态。
fiber reconciler
挂载阶段
首次执行ReactDOM.render(<App />, document.getElementById('root'))会创建一个fiberRoot作为整个应用的fiber根节点;另外,在一个应用中ReactDOM.render可以在不同的代码位置多次执行,所以需要额外的rootFiber代表当前渲染的组件树的根节点。
fiberRoot具有一个current属性指向当前渲染的组件树的根节点,也就是
fiberRoot.current = rootFiber;
但是由于是首次执行的挂载阶段,所以此时current = rootFiber = null。所以需要先递归遍历整个组件树,不断的创建新的fiber节点并通过fiber.child、fiber.sibling等属性关联父子节点、兄弟节点等,最终形成一棵work-in-progress fiber tree。
然后将fiberRoot的current属性指向该work-in-progress fiber tree的根节点,然后提交到renderer进行渲染。

更新阶段
在组件更新的时候会创建新的work-in-progress fiber,但是此时已经存在current fiber,它们之间通过alternate属性进行关联,所以它们之间会通过 diff 算法进行对比,判断是否复用之前current fiber的状态。
fiber 解决了什么问题
fiber reonciler主要是为了解决stack reconciler的以下问题:
- 支持返回多个元素;
- 避免遍历更新队列一次性操作 DOM 可能阻塞 UI 渲染的问题;
- 更新处理时把任务进行优先级拆分,保证 UI 及时更新;